점진적 인증 전환과 게이트웨이 책임분리 패턴
NOTE
서비스 간(M2M) 내부 통신에 인증을 새로 도입할 때 기존 호출자를 깨뜨리지 않고 단계적으로 강제하는 shadow→deny 전환 패턴과, 여러 외부 파트너와 통신하는 게이트웨이 클라이언트의 책임분리 설계.
1. 내부 통신 인증 — shadow 모드로 시작해서 deny로 전환
기존에 인증 헤더 없이 호출하던 배치/서비스가 여러 곳에 흩어져 있는 상태에서, 갑자기 인증을 강제(deny)하면 그 호출자들이 전부 깨진다. 반대로 인증을 아예 안 만들면 내부 통신이 영원히 무방비 상태로 남는다.
1단계 — shadow(관찰) 모드
헤더가 없어도 요청을 통과시킨다.
단, "헤더 없음"을 로그/메트릭으로 남겨 어떤 호출자가 아직 인증을 안 붙였는지 파악한다.
2단계 — 호출자별로 인증 부착
파악된 호출자들에게 순서대로 인증 로직을 붙인다.
3단계 — deny(강제) 모드로 전환
모든 호출자가 인증을 붙인 것이 확인되면, 헤더 없는 요청을 거부하도록 정책을 바꾼다.핵심: 정책 전환 지점(shadow ↔ deny)을 설정값 하나로 두면, 실제 강제 전환은 배포 없이 설정 변경만으로 가능하다. “아직 deny로 전환 안 됨”이라는 상태 자체가 남은 작업(배치 쪽 인증 부착)을 드러내는 체크리스트 역할을 한다.
이 패턴은 API Gateway/인증 미들웨어를 새로 도입하는 모든 상황에 적용 가능하다 — 새 인증을 만들 때 “기존 호출자를 다 찾아서 동시에 고친다”는 빅뱅 전환은 위험하므로, 관찰(shadow) → 개별 전환 → 강제(deny) 순서를 기본값으로 삼는다.
2. 여러 외부 파트너와 통신하는 게이트웨이 — 클라이언트는 transport만
여러 외부 파트너(각기 다른 응답 형식)와 통신할 때, “통신”과 “응답 해석”을 한 클래스에 몰아넣으면 파트너가 늘어날수록 그 클래스가 비대해지고 특정 파트너의 응답 형식 변경이 다른 파트너 처리 로직에도 영향을 줄 위험이 생긴다.
[호출부 A] ─┐
[호출부 B] ─┼─▶ GatewayClient (transport 전용)
[호출부 C] ─┘ │
├─ base URL 조립
├─ 인증 헤더 부착
└─ HTTP 송신 → 원시 응답(raw string) 반환
│
(파싱/resultCd 해석은 각 호출부 책임)GatewayClient(또는 유사 이름의 클라이언트)는 “어디로, 어떻게 보낼지”만 안다 — URL 조립, 인증, 타임아웃, 전송.- 응답 해석은 호출부가 한다 — 파트너마다 응답 shape이 다르고, 벌크 응답(리스트)과 단건 응답이 섞여 있으면 클라이언트 레벨에서 통합 파싱을 시도하는 순간 벌크 응답에서 깨진다.
- 이렇게 분리해두면, 인증 방식을 바꾸는 등 transport 관련 변경은 클라이언트 한 곳만 고치면 전체 호출부에 반영된다(위 1절의 shadow→deny 전환도 이 클라이언트의 전송 메서드 한 곳만 바꾸면 되도록 설계할 수 있다).
응답 규격을 억지로 통일하지 않는다
내부 표준 응답 포맷(예: 공통 resultCode 봉투)이 있더라도, 외부 게이트웨이의 응답까지 그 포맷에 강제로 맞추려 하면 파트너가 다양할수록 변환 로직이 산으로 간다. 라우팅과 결과코드 체계만 내부 표준에 맞추고, 나머지 계약(리스트 구조 등)은 게이트웨이 고유 방식을 유지하는 편이 현실적이다.
3. 요약 체크리스트
[ ] 새 인증을 붙일 때 기존 호출자를 한 번에 깨뜨리지 않는가?
→ shadow(관찰) 모드로 먼저 배포, 호출자 목록 확보 후 개별 전환, 마지막에 deny
[ ] 외부 파트너 다수와 통신하는 클라이언트가 응답 파싱까지 떠맡고 있지 않은가?
→ transport(전송) 책임과 파싱 책임을 분리, 파싱은 호출부로
[ ] 벌크 응답과 단건 응답이 섞여 있는데 공통 파싱을 시도하고 있지 않은가?
→ 통합 파싱 금지, 엔드포인트별 shape 그대로 반환관련 문서
- (백엔드·데이터처리) 결과코드 체계 중앙화 설계 패턴 — 이 문서에서 “라우팅과 결과코드 체계만 내부 표준에 맞춘다”고 언급한 결과코드 체계 자체를 중앙화하는 설계 패턴을 다루는 문서